package com.tgh.gles2.c8.depthbuffer;

import android.content.Context;
import android.opengl.GLES11Ext;
import android.opengl.GLES20;
import com.tgh.gles2.BaseRenderer;
import com.tgh.utils.*;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import java.nio.ByteBuffer;

import static android.opengl.GLES20.*;
import static com.tgh.utils.GLShaderManager.*;

/**
 * Created by emellend on 13-5-23.
 */
public class DepthRenderer extends BaseRenderer{


    private int[] rendererBuffers;

    public DepthRenderer(Context context) {
        super(context);
        modelViewMatrix=new GLMatrixStack();
        projectionMatrix=new GLMatrixStack();
        transformPipleLine=new GLGeometryTransform();
        cameraFrame=new GLFrame();
        torusBatch = new GLTriangleBatch();
        if (!torusBatch.loadDataFromSD("torus_04_015_35_35")) {
            torusBatch =GLTools.makeTorus(0.4f, 0.15f, 35, 35);
            torusBatch.cacheDataToSD("torus_04_015_35_35");
        }
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        shaderManager = new GLShaderManager();
        shaderManager.initStockShader();
        glEnable(GL_DEPTH_TEST);
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        glViewport(0,0,width,height);
        screenWidth=width;
        screenHeight=height;
        initTexture();
        initBuffer();

        viewFrustum=new GLFrustum(35f,(float)width/(float)height,1,100);
        projectionMatrix.loadMatrix(viewFrustum.getProjectionMatrix());
        transformPipleLine.setMatrixStack(modelViewMatrix,projectionMatrix);
        generateOrtho2DMat();
        cameraFrame.moveForward(-3.5f);
        cameraFrame.moveUp(-0.4f);
    }

    @Override
    public void onDrawFrame(GL10 gl) {
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
        modelViewMatrix.pushMatrix();
            glBindFramebuffer(GL_FRAMEBUFFER,framebuffer[0]);
            Matrix44f cameraMatrix = cameraFrame.getCameraMatrix(false);
            modelViewMatrix.multMatrix(cameraMatrix);
            Vector4f transformedLight=new Vector4f();
            Math3D.transformVector4(transformedLight,vLightPos,modelViewMatrix.getMatrix());
            shaderManager.useStockShader(
                    ShaderType.POSITION_LIGHT,
                    modelViewMatrix.getMatrix().getArray(),
                    projectionMatrix.getMatrix().getArray(),
                    transformedLight.toArray(),
                    vGreen
                    );
            torusBatch.draw();
        modelViewMatrix.popMatrix();

        projectionMatrix.pushMatrix();
            projectionMatrix.loadIdentity();
            projectionMatrix.multMatrix(orthoMatrix);
            glBindFramebuffer(GL_FRAMEBUFFER, 0);
            shaderManager.useStockShader(
                    ShaderType.TEXTURE_REPLACE,
                    transformPipleLine.getModelViewProjectionMatrix().getArray(),
                    0
            );
            glDisable(GL_DEPTH_TEST);
            screenQuad.draw();
            glEnable(GL_DEPTH_TEST);
        projectionMatrix.popMatrix();
    }

    @Override
    public void onSurfaceDestroyed() {

    }

    private void generateOrtho2DMat() {
        orthoMatrix = new Matrix44f();
        orthoMatrix.loadOrtho(0, screenWidth, 0, screenHeight, -1, 1);

        screenQuad = new GLBatch(GLES20.GL_TRIANGLE_STRIP, 4);
        screenQuad.color(0.0f, 1.0f, 0.0f, 1.0f);
        screenQuad.multiTexCoord(0, 0.0f, 0.0f);
        screenQuad.vertex(0.0f, 0.0f, 0.0f);

        screenQuad.color(0.0f, 1.0f, 0.0f, 1.0f);
        screenQuad.multiTexCoord(0, 1.0f, 0.0f);
        screenQuad.vertex((float)screenWidth, 0.0f, 0.0f);

        screenQuad.color(0.0f, 1.0f, 0.0f, 1.0f);
        screenQuad.multiTexCoord(0, 0.0f, 1.0f);
        screenQuad.vertex(0.0f, (float)screenHeight, 0.0f);

        screenQuad.color(0.0f, 1.0f, 0.0f, 1.0f);
        screenQuad.multiTexCoord(0, 1.0f, 1.0f);
        screenQuad.vertex((float)screenWidth, (float)screenHeight, 0.0f);
        screenQuad.end();
    }

    private void initTexture(){
        texture = GLTools.genTextures(2);

        glBindTexture(GL_TEXTURE_2D, texture[COLOR_TEXTURE]);
        glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB,screenWidth,screenHeight,0,GL_RGB,GL_UNSIGNED_SHORT_5_6_5,null);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);

        glBindTexture(GL_TEXTURE_2D, texture[DEPTH_TEXTURE]);
        glTexImage2D(GL_TEXTURE_2D,0,GL_DEPTH_COMPONENT,screenWidth,screenHeight,0,GL_DEPTH_COMPONENT,GL_UNSIGNED_SHORT,null);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
    }

    private void initBuffer(){
   /*     framebuffer = new int[1];
        glGenFramebuffers(1, framebuffer, 0);

        rendererBuffers = new int[2];
        glGenRenderbuffers(2, rendererBuffers,0);

        glBindRenderbuffer(GL_RENDERBUFFER,rendererBuffers[0]);
        glRenderbufferStorage(GL_RENDERBUFFER,GL_DEPTH_COMPONENT16,screenWidth,screenHeight);

        glBindRenderbuffer(GL_RENDERBUFFER,rendererBuffers[1]);
        glRenderbufferStorage(GL_RENDERBUFFER,GL_RGB5_A1, screenWidth,screenHeight);

        glBindFramebuffer(GL_FRAMEBUFFER, framebuffer[0]);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_RENDERBUFFER,rendererBuffers[0]);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_RENDERBUFFER,rendererBuffers[1]);

        int status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
        GLTools.checkFrameBufferComplete(status);*/


        framebuffer = new int[1];
        glGenFramebuffers(1, framebuffer,0);
        texture=new int[2];
        glGenTextures(2, texture,0);
        glBindTexture(GL_TEXTURE_2D, texture[COLOR_TEXTURE]);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screenWidth, screenHeight,0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, null);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);

        depthRender = new int[1];
        glGenRenderbuffers(1, depthRender,0);
        glBindRenderbuffer(GL_RENDERBUFFER,depthRender[0]);
        glRenderbufferStorage(GL_RENDERBUFFER,GL_DEPTH_COMPONENT16,screenWidth,screenHeight);



/*        glBindTexture(GL_TEXTURE_2D, texture[DEPTH_TEXTURE]);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, screenWidth, screenHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT,null);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);*/

        glBindFramebuffer(GL_FRAMEBUFFER, framebuffer[0]);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D, texture[COLOR_TEXTURE], 0);
//        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,GL_TEXTURE_2D, texture[DEPTH_TEXTURE], 0);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_RENDERBUFFER,depthRender[0]);
        int status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
        GLTools.checkFrameBufferComplete(status);
    }

    private int screenWidth,screenHeight;

    private GLShaderManager shaderManager;
    private int[] texture;
    private int[] framebuffer;
    private int[] depthRender;
    private static final int COLOR_TEXTURE=0;
    private static final int DEPTH_TEXTURE=1;
    private GLMatrixStack modelViewMatrix;
    private GLMatrixStack projectionMatrix;
    private Matrix44f orthoMatrix;
    private GLGeometryTransform transformPipleLine;
    private GLFrame cameraFrame;
    private GLFrustum viewFrustum;
    private GLBatch screenQuad;
    private Vector4f vLightPos=new Vector4f(0,3,1,1);
    private float[] vGreen={0,1,0,1};
    private GLTriangleBatch torusBatch;
}
